#include "CoordCom.h"

void sendInfoToAllSensors(unsigned char* info, int dataLen)
{
    FrameAPI myApiFrame;

    unsigned char adresseDEST_H[4] = {0x00, 0x00, 0x00, 0x00};
    unsigned char adresseDEST_L[4] = {0x00, 0x00, 0xFF, 0xFF};
    unsigned char adresseDEST_16bits_Broadcast[2] = {0xFF, 0xFE};

    makeDataTransmitFrame(&myApiFrame, info, dataLen, adresseDEST_H, adresseDEST_L,adresseDEST_16bits_Broadcast);

    sendAPI(myApiFrame);

    waitForTransmitStatusPacket();
}

void sendInfoToOneSensor(unsigned char* info, unsigned char* nodeID, int dataLen)
{
    FrameAPI myApiFrame;
    unsigned char adresseDEST_H[4] = {0x00, 0x00, 0x00, 0x00};
    unsigned char adresseDEST_L[4] = {0x00, 0x00, 0x00, 0x00};
    unsigned char adresseDEST_16bits[2] = {0xFF,0xFE};

    if (getDestinationAddressFromRouteTable(nodeID, adresseDEST_H, adresseDEST_L))
    {
        makeDataTransmitFrame(&myApiFrame, info, dataLen, adresseDEST_H, adresseDEST_L, adresseDEST_16bits);
    }
    else
    {
        networkDiscover();
        getDestinationAddressFromRouteTable(nodeID, adresseDEST_H, adresseDEST_L);
        makeDataTransmitFrame(&myApiFrame, info, dataLen, adresseDEST_H, adresseDEST_L, adresseDEST_16bits);
    }

    displayAPIFrame(myApiFrame);

    sendAPI(myApiFrame);

    waitForTransmitStatusPacket();
}

char getNodeDiscoveryTimOut()
{
    unsigned char ATCmd_NT[] = "NT";
    unsigned char void_parameter[1];
    void_parameter[0] = '\0';
    FrameAPI myApiFrame;

    makeATFrame(&myApiFrame, ATCmd_NT, void_parameter, 0x52);
    displayAPIFrame(myApiFrame);
    sendAPI(myApiFrame);

    recept(&myApiFrame,10);
    return myApiFrame.content.data[6]/10;
}

void networkDiscover()
{
    unsigned char void_parameter[1];
    unsigned char ND_TimeOut[12];
    unsigned char ATCmd_ND[] = "ND";
    unsigned char timeOut = 0;
    FrameAPI myApiFrame;
    void_parameter[0] = '\0';
    timeOut = getNodeDiscoveryTimOut();
    makeATFrame(&myApiFrame,ATCmd_ND, void_parameter, 0x53);
    sendAPI(myApiFrame);
    do
    {
        timeOut = recept(&myApiFrame,timeOut);
        if (timeOut > 0)
        {
            parseResponse_ATND(myApiFrame);
        }
    } while(timeOut > 0);
}

void parseResponse_ATND(FrameAPI fApi)
{
    unsigned char nodeId[20];
    unsigned char destH[4];
    unsigned char destL[4];
    int iCpt = 0;
    while(fApi.content.frame.api.atResponse.cmdData[iCpt + 2])
    {
        destH[iCpt] = fApi.content.frame.api.atResponse.cmdData[iCpt + 2];
        destL[iCpt] = fApi.content.frame.api.atResponse.cmdData[iCpt + 6];
    }
    iCpt = 0;
    while(fApi.content.data[iCpt + 10] != 0)
    {
        nodeId[iCpt] = fApi.content.frame.api.atResponse.cmdData[iCpt + 10];
        iCpt ++;
    }
    nodeId[iCpt] = 0;
    addRouteTableEntry(nodeId,destH,destL);
}

void initCoord(void)
{
    gl_RouteTable.curTableIndex = 0;
    gl_SleepTimeLeft = 0;
    initClock(10);
    initPortSerie("COM7");
}

void handleDataPacket(FrameAPI fApi)
{
    int iCpt = 0;
    unsigned char curChar = 0;
    int iIndex  = 0;

    int i;

    unsigned char requested_NodeID[4];
    printf("<?>DEBUG - Packet received\n");
    switch(fApi.content.frame.api.receivePacket.rcvData[0])
    {
        case SENSOR_DATA_PACKET :
            printf("<?>DEBUG - Data packet\n");
            parseSensorData(fApi);
            break;

        case SENSOR_REGISTER_REQUEST :
            do
            {
                curChar = fApi.content.frame.api.receivePacket.rcvData[iCpt + 1];
                requested_NodeID[iCpt] = curChar;
                iCpt ++;
            }while(curChar != 0);
            requested_NodeID[iCpt] = 0;

            printf("<?>DEBUG - Register request for NodeId : %s\n",requested_NodeID);

            iIndex = tryGetEntryIndexFromAddress(fApi.content.frame.api.receivePacket.srcAdd64H, fApi.content.frame.api.receivePacket.srcAdd64L);
            putchar('\n');
            putchar('>');
            putchar('>');
            putchar('\t');
            for(i = 0; i < 4 ; i++)
            {
                printf("0x%x ", (unsigned char)fApi.content.frame.api.receivePacket.srcAdd64H[i]);
            }
            putchar('\t');
            for(i = 0; i < 4 ; i++)
            {
                printf("0x%x ", (unsigned char)fApi.content.frame.api.receivePacket.srcAdd64L[i]);
            }
            putchar('\n');
            if(iIndex != -1)
            { // if there is already an entry with that 64 bit address then
                if(stringCompare(requested_NodeID, gl_RouteTable.Entries[iIndex].entry_NI) != 1)
                { // if the node ID is different then
                    // ask the device to change his node ID
                    printf("<?>DEBUG - A device is already register with the nodeID : %s\n", gl_RouteTable.Entries[iIndex].entry_NI);
                    sendRegisterResponse(gl_RouteTable.Entries[iIndex].entry_NI, FALSE);
                }
                else
                { // else
                    // send an OK response
                    printf("<?>DEBUG - Device's already register\n");
                    sendRegisterResponse(requested_NodeID,TRUE);
                }
            }
            else
            {
                iIndex = tryGetEntryIndex(requested_NodeID);
                if(iIndex != -1)
                { // if there is already an entry with that node ID
                    // send a Not Ok response with a new nodeID
                    unsigned char newNodeID[4];
                    newNodeID[0] = 'c';
                    newNodeID[1] = gl_RouteTable.curTableIndex/10 + 0x30;
                    newNodeID[2] = gl_RouteTable.curTableIndex%10 + 0x30;
                    newNodeID[3] = '\0';
                    printf("<?>DEBUG - This node id is already registred. Device registered with a new nodeID : %s\n",newNodeID);
                    addRouteTableEntry(newNodeID, fApi.content.frame.api.receivePacket.srcAdd64H, fApi.content.frame.api.receivePacket.srcAdd64L);
                    displayRouteTable();
                    sendRegisterResponse(newNodeID,FALSE);
                }
                else
                {// else
                    // send an OK response
                    printf("<?>DEBUG - Register OK\n");
                    addRouteTableEntry(requested_NodeID, fApi.content.frame.api.receivePacket.srcAdd64H, fApi.content.frame.api.receivePacket.srcAdd64L);
                    sendRegisterResponse(requested_NodeID,TRUE);
                }
            }
            break;
    }
}

void sendRegisterResponse(unsigned char nodeID_dest[4], char ok)
{
    unsigned char data[16];
    char dataLen = 2;
    data[0] = COORD_REGISTER_RESPONSE;
    if (ok == TRUE)
    {
        data[1] = REGISTER_SUCCESS;
    }
    else
    {
        data[1] = REGISTER_FAILURE;
        dataLen += stringCopy(nodeID_dest, data + 2);
    }
    sendInfoToOneSensor(data, nodeID_dest, dataLen);
}

void parseSensorData(FrameAPI fApi)
{
    unsigned char iIndex = 0;
    unsigned char iIndexRt_MatchingDevice = 0;
    int iFrameSize = fApi.length_MSB * 256 + fApi.length_LSB;
    FILE* fOut = fopen("out.tmp","a+");

    unsigned char buffer[5];

    while(fApi.content.frame.api.receivePacket.rcvData[iIndex + 1] != '*')
    {
        buffer[iIndex] = fApi.content.frame.api.receivePacket.rcvData[iIndex + 1];
        iIndex ++;
    }
    buffer[iIndex] = '\0';

    iIndexRt_MatchingDevice = tryGetEntryIndex(buffer);

    if(iIndexRt_MatchingDevice == -1)
    {
        printf("<!>ERROR - Data Packet Received From unregistered Device - Ignored\n");
        fclose(fOut);
        return;
    }

    fprintf(fOut,"%d - ", getCurDate());
    printf("%d - ", getCurDate());

    gl_RouteTable.Entries[iIndexRt_MatchingDevice].entry_ErrorCount = 0;
    fprintf(fOut,"%s", buffer);
    printf("%s", buffer);

    buffer[0] = fApi.content.frame.api.receivePacket.rcvData[iIndex + 1];
    while(iIndex < iFrameSize)
    {
        if(fApi.content.data[iIndex] == '*')
        {
            fprintf(fOut,";");
            printf(";");
        }
        else
        {
            fprintf(fOut,"%x", (unsigned char)fApi.content.data[iIndex]);
            printf("%x", (unsigned char)fApi.content.data[iIndex]);
        }
        iIndex ++;
    }
    printf("\n");
    fclose(fOut);
}

int getCurDate()
{
    return 111111;
}

void sendRequestData(unsigned char nodeID_dest[4])
{
    unsigned char data[1];
    data[0] = COORD_DATA_REQUEST;
    sendInfoToOneSensor(data, nodeID_dest,1);
}

int requestDataFromFirstNonResponding(void)
{
    int iCpt;
    for(iCpt = 0 ; iCpt < gl_RouteTable.curTableIndex ; iCpt ++ )
    {
        if((gl_RouteTable.Entries[iCpt].entry_ErrorCount > 0 )&&(gl_RouteTable.Entries[iCpt].entry_ErrorCount < 3))
        {
            sendRequestData(gl_RouteTable.Entries[iCpt].entry_NI);
            return iCpt;
        }
    }
    return -1;
}

void sendRequestSleepModeToAllDevice(int sleepTime)
{
    unsigned char data[3];
    data[0] = COORD_SLEEP_REQUEST;
    data[1] = sleepTime/256;
    data[2] = sleepTime%256;
    sendInfoToAllSensors(data,3);
}
